#pragma once

 /*
 * TCP server for anet implementation
 * anet��TCP������
 * Copyright (C) 2019 - 2023 gavingqf(gavingqf@126.com)
 *
 *    Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *    http://www.boost.org/LICENSE_1_0.txt)
 */
#include <any>
#include "acceptor.hpp"
#include <string>
#include <assert.h>
#include "event_loop.hpp"
#include "anet.hpp"
#include "asio/detail/noncopyable.hpp"
#include "http_info.hpp"

namespace anet {
	namespace tcp {
		static const char *gDefaultAddr = "0";
		class CServer : asio::noncopyable {
		public:
			explicit CServer(CEventLoop &loop) : m_acceptor(loop) {
			}
			virtual ~CServer() {
				this->stop();
			}

		public:
			// set max connection num, where num == 0 is unlimited.
			void setMaxConnectNum(int num) {
				m_acceptor.setMaxConnectNum(num);
			}

			void setAny(std::any any) {
				this->m_attach = any;
			}
			std::any getAny() {
				return m_attach;
			}

			void setSessionFactory(ISessionFactory *factory) {
				m_acceptor.setSessionFactory(factory);
			}
			void setPacketParser(ICodec *parser) {
				m_acceptor.setPacketParser(parser);
			}

			// start server with ip and port.
			bool start(const std::string &addr, unsigned short port) {
				std::string realIP(addr);
				if (addr == gDefaultAddr) { 
					realIP = "0.0.0.0"; 
				}
				return m_acceptor.start(realIP, port);
			}
			bool start(unsigned short port) {
				return start(gDefaultAddr, port);
			}

			// start server with ip:port address
			bool start(const std::string& addr) {
				std::vector<std::string> vec;
				anet::http::strSplits(addr, ":", vec);
				if (vec.size() >= 2) {
					return this->start(vec[0], std::stoi(vec[1]));
				} else {
					return false;
				}
			}

			// stop server
			void stop() {
				m_acceptor.stop();
			}

		protected:
			CAcceptor m_acceptor;
			std::any m_attach;
		};

		// simple server class for user.
		class Server final {
		public:
			explicit Server(unsigned int size = 0) : m_loop(size), m_server(m_loop) {}
			virtual ~Server() = default;

		public:
			CServer& proxy() {
				return m_server;
			}
			CServer* operator->() {
				return &m_server;
			}

		protected:
			// event loop object.
			CEventLoop m_loop;

			// server object.
			CServer    m_server;
		};
	}
}
